#!/usr/bin/env python2
import os
import sys
import socket
import time
import subprocess
import fcntl
import types
import errno
import random
import threading
from time import sleep, ctime

test_path = os.path.abspath(os.getcwd() + "/..") #"/tmp/test/fusionstack/lich"
lichd = test_path + "/lich/sbin/lichd"
lich = test_path + "/lich/libexec/lich"
lich_admin = test_path + "/lich/libexec/lich.admin"
#lichdata = test_path + "/test/data"
#log_cmd = " >> " + test_path + "/lich.log 2>&1"
log_cmd = ""

#sys.path.append(test_path + "/admin")
from list_test import List_test
from utils import _print1, _print2, _print3, _get_value, Exp, _dwarn, _dmsg, _derror
from node import Node
from cluster import Cluster

class Lich:
    def __init__ (self, list_count):
        self.stopped = 0
        self.name = "Lich test"
        self.list = {}
        self.list_init("/", list_count)
        self.list_init("/ns1", list_count)
        self.list_init("/ns2/bk1", list_count)
        cluster = Cluster()
        hostname = socket.gethostname()
        cluster.init()
        self.node = Node()
        self.instence_count = len(self.node.instences)
        self.err = None;
        self.errno = 0;

    def start_all(self):
        pass
        #self.node.start()

    def restart_all(self):
        self.node.stop()
            
    def create(self, name):
        cmd = lich + " --create %s" %(name)
        _print3 (cmd)
        return subprocess.call(cmd, shell=True)
        
    def clone(self, _from, _to):
        cmd = lich + " --clone %s %s" %(_from, _to)
        _print3 (cmd)
        return subprocess.call(cmd, shell=True)

    def list_init(self, path, count):
        self.list.update({path: List_test(count, path, lich, log_cmd)})

    def list_insert(self, path):
        list_test = self.list[path]
        for i in range(list_test.count):
            list_test.insert(i)

    def list_check(self, path):
        list_test = self.list[path]
        for i in range(list_test.count):
            if (self.errno):
                raise Exp(self.errno, self.err)
            list_test.check(i)
        
    def kill(self, i):
        if (i == -1):
            i = random.randint(0, self.instence_count)

        _dmsg("stop instence[%s]" % (i))
        self.node.instences[i].stop()

    def scan(self):
         while (1):
            cmd = lich + " --recover --scan / %s" % (log_cmd)
            _print3 (cmd)
            ret = subprocess.call(cmd, shell=True)
            if (ret):
                if (ret == errno.EAGAIN):
                    time.sleep(1)
                    continue;
                else:
                    return ret
            else:
                break

    def fail(self, scan):
        for i in range(self.instence_count):
            retry = 0
            while (1):
                if (self.node.instences[i].running()  == False):
                    if (retry < 10):
                        _print2("instence %u not online, retry %u" %(i, retry))
                        retry += 1
                        sleep(1)
                    else:
                        _print2("instence %u not online" %(i))
                        return errno.EPERM
                else:
                    break;

        i = random.randint(0, self.instence_count - 1)

        _dmsg("stop instence[%s]" % (i))
        ret = self.node.instences[i].stop()
        if (ret):
            return ret

        sleep(10)

        if (scan):
            self.scan()
        else:
            sleep(60)

        sleep(2)

        ret = self.node.instences[i].start()
        if (ret):
            return ret
        return 0

    def quorum_check(self):
        len = self.node.instences[0].quorum_size()

        for i in range(self.instence_count):
            if (self.node.instences[i].quorum_size() != len):
                _print1("wait instence %u quorum sync..." % (i))
                return False
        return True

    def fail_simulate_loop(self):
        while True:
            if self.quorum_check():
                break;
            else:
                sleep(1)

        #os.system("mkdir -p /dev/shm/lich4/msgctl/")
        #os.system("echo 1 > /dev/shm/lich4/msgctl/backtrace")

        i = 0
        while True:
            _print1("fail_simulate %s %u time %f ..." %(self.name, i, time.time()))

            if ((i + 1) % 2 == 0):
                scan = 1
            else:
                scan = 0

            ret = self.fail(scan)
            if (ret):
                self.err = "fail_simulate error %s %u" %(self.name, i)
                self.errno = ret
                _print2(self.err)
                exit(ret)

            _print1("fail simulate %s %u ok time %f" %(self.name, i, time.time()));

            sleep(1)

            i = i + 1
            if (self.stopped):
                break
        
    def fail_simulate(self):
        sleep(10)
        t = threading.Thread(target=self.fail_simulate_loop)#, args = self)
        t.start()

    def destroy(self):
        self.stopped = 1
